package com.wechat.page.chat.popup;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import com.swak.entity.YesNo;
import com.swak.fx.support.Action;
import com.swak.fx.support.FXMLView;
import com.swak.fx.support.Popup;
import com.swak.fx.support.ui.UI;
import com.swak.fx.support.ui.UI.Locations;
import com.swak.fx.support.ui.UIAction;
import com.swak.fx.support.ui.UIDivide;
import com.swak.ui.Event;
import com.swak.utils.Lists;
import com.swak.utils.StringUtils;
import com.swak.utils.time.DateTimes;
import com.wechat.Cons;
import com.wechat.dto.ChatDTO;
import com.wechat.enums.ContactType;
import com.wechat.page.api.ChatApi;

import javafx.beans.binding.Bindings;
import javafx.beans.property.LongProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.HPos;
import javafx.scene.Node;
import javafx.scene.control.Separator;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.util.Duration;

/**
 * OpsPopup.
 * 
 * @author DELL
 */
@FXMLView(title = "操作", value = "OpsPopup.fxml", css = "OpsPopup.css")
public class OpsPopup extends Popup {

	static enum ActionCmd {
		Top, Unread, Alert, Md_Name, Md_Alias, Open_InWindow, Contact, Hide, Clear, Del
	}

	@Autowired
	private ChatApi chatApi;

	private List<Object> actions = Lists.newArrayList();

	public OpsPopup() {
		this.actions.add(Action.of().setCommand(ActionCmd.Top).setText("置顶").setActiveText("取消置顶")
				.bindActive(Bindings.createBooleanBinding(() -> {
					ChatDTO chat = this.chatProperty.get();
					return chat != null && chat.getIsTop() != null && chat.getIsTop() == YesNo.Yes.getType();
				}, this.chatProperty, this.refreshProperty)));
		this.actions.add(Action.of().setCommand(ActionCmd.Unread).setText("标为未读"));
		this.actions.add(Action.of().setCommand(ActionCmd.Alert).setText("消息免打扰").setActiveText("取消消息免打扰")
				.bindActive(Bindings.createBooleanBinding(() -> {
					ChatDTO chat = this.chatProperty.get();
					return chat != null && chat.getIsAlert() != null && chat.getIsAlert() == YesNo.No.getType();
				}, this.chatProperty, this.refreshProperty)));
		this.actions.add(Action.of().setCommand(ActionCmd.Md_Name).setText("修改群聊名称")
				.bindVisable(Bindings.createBooleanBinding(() -> {
					ChatDTO chat = this.chatProperty.get();
					return chat != null && chat.getType() != null && chat.getType() == ContactType.Chat_Room.getType();
				}, this.chatProperty, this.refreshProperty)));
		this.actions.add(Action.of().setCommand(ActionCmd.Md_Alias).setText("设置备注")
				.bindVisable(Bindings.createBooleanBinding(() -> {
					ChatDTO chat = this.chatProperty.get();
					return chat != null && chat.getType() != null && chat.getType() == ContactType.Chat_Room.getType();
				}, this.chatProperty, this.refreshProperty)));
		this.actions.add(Action.of().setCommand(ActionCmd.Open_InWindow).setText("在独立窗口中打开"));
		this.actions.add(Action.of().setCommand(ActionCmd.Contact).setText("添加到通讯录").setActiveText("从通讯录中删除")
				.bindVisable(Bindings.createBooleanBinding(() -> {
					ChatDTO chat = this.chatProperty.get();
					return chat != null && chat.getType() != null && chat.getType() == ContactType.Chat_Room.getType();
				}, this.chatProperty, this.refreshProperty))
				.bindActive(Bindings.createBooleanBinding(() -> {
					ChatDTO chat = this.chatProperty.get();
					return chat != null && chat.getIsFriend() != null && chat.getIsFriend() == YesNo.Yes.getType();
				}, this.chatProperty, this.refreshProperty)));
		this.actions.add(new UIDivide());
		this.actions.add(Action.of().setCommand(ActionCmd.Hide).setText("不显示聊天"));
		this.actions.add(Action.of().setCommand(ActionCmd.Clear).setText("清空聊天"));
		this.actions.add(Action.of().setCommand(ActionCmd.Del).setText("删除聊天"));
	}

	@Override
	public void initializeParts() {
		super.initializeParts();
		this.animatedProperty().set(true);
		this.locationProperty().set(Locations.LEFT_TOP);
	}

	@Override
	public void layoutParts() {
		super.layoutParts();
		this.clearChild();
		int rows = 0;
		for (Object obj : actions) {
			if (obj instanceof Action) {
				Action action = (Action) obj;
				if (!action.isVisable()) {
					continue;
				}
				UIAction actionBtn = new UIAction().setIcon(action.getGlyph())
						.setText(
								action.isActive() ? StringUtils.defaultIfBlank(action.getActiveText(), action.getText())
										: action.getText())
						.setTextCenter(false).setCommand(action.getCommand());
				this.addChild(actionBtn);
				GridPane.setConstraints(actionBtn, 0, rows++);
				GridPane.setHgrow(actionBtn, Priority.ALWAYS);
				GridPane.setHalignment(actionBtn, HPos.CENTER);
			} else if (obj instanceof Separator) {
				Separator separator = (Separator) obj;
				this.addChild(separator);
				GridPane.setConstraints(separator, 0, rows++);
				GridPane.setHgrow(separator, Priority.ALWAYS);
				GridPane.setHalignment(separator, HPos.CENTER);
			}
		}
	}

	@Override
	public void setupEventHandlers() {
		super.setupEventHandlers();
		this.root.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> {
			Node node = (Node) e.getTarget();
			ActionCmd cmd = node.hasProperties() ? (ActionCmd) node.getProperties().get(UI.Conts.Cmd_Key) : null;
			if (cmd != null) {
				this.$run(() -> this.execCmd(cmd));
			}
		});
	}

	private void execCmd(ActionCmd cmd) {
		switch (cmd) {
		case Top: {
			this.execCmd_Top();
			break;
		}
		case Unread: {
			this.execCmd_Unread();
			break;
		}
		case Alert: {
			this.execCmd_Alert();
			break;
		}
		case Md_Name: {
			this.execCmd_MdName();
			break;
		}
		case Md_Alias: {
			this.execCmd_MdAlias();
			break;
		}
		case Open_InWindow: {
			this.execCmd_OpenInWindow();
			break;
		}
		case Contact: {
			this.execCmd_Contact();
			break;
		}
		case Hide: {
			this.execCmd_Hide();
			break;
		}
		case Clear: {
			this.execCmd_Clear();
			break;
		}
		case Del: {
			this.execCmd_Del();
			break;
		}
		default:
			throw new IllegalArgumentException("Unexpected value: " + cmd);
		}
	}

	// **********************************
	// 执行命令 - 开始
	// **********************************
	private void execCmd_Top() {
		ChatDTO chat = this.chatProperty().get();
		this.chatApi.updateFlag(ChatDTO.of().setId(chat.getId())
				.setIsTop(chat.getIsTop() != null && chat.getIsTop() == YesNo.Yes.getType() ? YesNo.No.getType()
						: YesNo.Yes.getType()))
				.thenAccept(res -> this.postCmd(ActionCmd.Top, res));
	}

	private void execCmd_Unread() {
		ChatDTO chat = this.chatProperty().get();
		this.chatApi.updateFlag(ChatDTO.of().setId(chat.getId()).setUnReadCount(1))// 操作unread
				.thenAccept(res -> this.postCmd(ActionCmd.Unread, res));
	}

	private void execCmd_Alert() {
		ChatDTO chat = this.chatProperty().get();
		this.chatApi.updateFlag(ChatDTO.of().setId(chat.getId())
				.setIsAlert(chat.getIsAlert() != null && chat.getIsAlert() == YesNo.Yes.getType() ? YesNo.No.getType()
						: YesNo.Yes.getType()))
				.thenAccept(res -> this.postCmd(ActionCmd.Alert, res));
	}

	private void execCmd_MdName() {

	}

	private void execCmd_MdAlias() {

	}

	private void execCmd_OpenInWindow() {

	}

	private void execCmd_Contact() {

	}

	private void execCmd_Hide() {

	}

	private void execCmd_Clear() {

	}

	private void execCmd_Del() {

	}

	private void postCmd(ActionCmd cmd, ChatDTO chat) {

		// 发送重新拉取未读消息的事件
		if (cmd == ActionCmd.Unread) {
			if (LOGGER.isDebugEnabled()) {
				LOGGER.debug("[聊天菜单] - 发送事件 ：{}", Cons.Event_Msg_Recv);
			}
			this.$post(Event.of().setKey(Cons.Event_Msg_Recv));
		}

		// 发送刷新
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("[聊天菜单] - 发送事件 ：{}", Cons.Event_Chat_Reload);
		}
		this.$post(Event.of().setKey(Cons.Event_Chat_Reload).setMessage(chat));
		this.$runUI(() -> this.popup.hide(Duration.ZERO));
	}

	// **********************************
	// 执行命令 - 结束
	// **********************************
	@Override
	public void setupBindings() {
		super.setupBindings();
		this.popup.showingProperty().addListener((ob, o, n) -> {
			if (n) {
				this.refreshProperty().set(DateTimes.nowMilli());
			}
		});
	}

	@Override
	public void setupValueChangedListeners() {
		super.setupValueChangedListeners();
		this.chatProperty().addListener((ob, o, chat) -> this.layoutParts());
		this.refreshProperty().addListener((ob, o, chat) -> this.layoutParts());
	}

	// ================================================================================
	// Properties
	// ================================================================================
	private final ObjectProperty<ChatDTO> chatProperty = new SimpleObjectProperty<>();
	private final LongProperty refreshProperty = new SimpleLongProperty();

	public ObjectProperty<ChatDTO> chatProperty() {
		return chatProperty;
	}

	public OpsPopup setChat(ChatDTO chat) {
		chatProperty().set(chat);
		return this;
	}

	public LongProperty refreshProperty() {
		return refreshProperty;
	}

	// ================================================================================
	// Instance
	// ================================================================================
	private static OpsPopup instance;

	public static OpsPopup newPopup() {
		if (instance == null) {
			synchronized (OpsPopup.class) {
				if (instance == null) {
					instance = OpsPopup.New(OpsPopup.class);
				}
			}
		}
		return instance;
	}
}
